﻿using Newtonsoft.Json.Linq;
using System;
using System.Diagnostics;
using System.IO;
using System.Net;

namespace XbmcManager
{
    /// <summary>
    /// Manages the connection with XBMC and sending and receiving of JSON
    /// </summary>
    class XbmcConnection
    {
        public String IpAddress;
        public int PortNumber;
        public String UserName;
        public String Password { private get;  set; }

        /// <summary>
        /// Constructor for the XbmcConnection Class. 
        /// Requires the data for connecting to XBMC.
        /// </summary>
        /// <param name="IpAddress">Typically "localhost" or "127.0.0.1"</param>
        /// <param name="PortNumber">XBMC Default is 80, We usually use 8080</param>
        /// <param name="UserName">The username for the HTTP connection in XBMC</param>
        /// <param name="Password">The password for the HTTP connection in XBMC</param>
        internal XbmcConnection(
            String IpAddress,
            int PortNumber, 
            String UserName, 
            String Password)
        {
            this.IpAddress = IpAddress;
            this.PortNumber = PortNumber;
            this.UserName = UserName;
            this.Password = Password;
        }

        /// <summary>
        /// Sends a JSON RPC command via HTTP POST to XBMC
        /// </summary>
        /// <param name="method">The name of the JSON RPC Method</param>
        /// <returns>Returns a JObject of the returned JSON</returns>
        public JObject SendJson(String method)
        {
            return this.SendJson(method, null);
        }

        /// <summary>
        /// Sends a JSON RPC command and parameters via HTTP POST to XBMC
        /// </summary>
        /// <param name="method">The name of the JSON RPC Method</param>
        /// <param name="args">A JObject containing the key/value pairs 
        /// of the parameter names and their values</param>
        /// <returns>Returns a JObject of the returned JSON response</returns>
        public JObject SendJson(String method, JObject args)
        {
            JObject jsonCommand = CreateJsonCommand(method, args);
            
            try
            {
                // Send JSON and receive the result in a string
                String result = this.Send(jsonCommand.ToString());

                return GetResponse(result);
            }
            catch (Exception e)
            {
                return SendErrorOccurred(method, args, e);
            }
        }

        private JObject CreateJsonCommand(String method, JObject args)
        {
            JObject jsonCommand = new JObject();                   //Created a JSON object
            jsonCommand.Add(new JProperty("jsonrpc", "2.0"));      //Add in the version number
            jsonCommand.Add(new JProperty("id", 1));               //This is unnecessary
            jsonCommand.Add(new JProperty("method", method));      //Add the method name
            if (args != null)
            {
                jsonCommand.Add(new JProperty("params", args));
            }

            return jsonCommand;
        }

        /// <summary>
        /// Uses HTTP Post to send a JSON RPC command and returns it's response.
        /// </summary>
        /// <param name="message">The JSON RPC String</param>
        /// <returns>A JObject of the response, 
        /// Be sure to check for errors if applicable</returns>
        private String Send(String message)
        {
            HttpWebRequest request = CreateRequest();

            WriteJsonString(message, request);

            HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();

            return GetResult(httpResponse);
        }

        private HttpWebRequest CreateRequest()
        {
            String url = "http://" + this.IpAddress + ":" + this.PortNumber + "/jsonrpc";
            HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
            NetworkCredential networkCredential = new NetworkCredential(this.UserName, this.Password);
            httpWebRequest.Credentials = networkCredential;
            httpWebRequest.ContentType = "application/json";
            httpWebRequest.Method = "POST";
            return httpWebRequest;
        }

        private static void WriteJsonString(String message, HttpWebRequest request)
        {
            using (StreamWriter streamWriter = new StreamWriter(request.GetRequestStream()))
            {
                streamWriter.Write(message);
            }
        }

        private static string GetResult(HttpWebResponse httpResponse)
        {
            using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
            {
                string result = streamReader.ReadToEnd();
                return result;
            }
        }

        /// <summary>
        /// // Parse the JSON and return the response.
        /// </summary>
        private static JObject GetResponse(String result)
        {
            JObject JsonResponse = JObject.Parse(result);
            return JsonResponse;
        }

        private static JObject SendErrorOccurred(String method, JObject args, Exception e)
        {
            Debug.Print("Sending JSON to XBMC failed for method: "
                + method + " with args: " + args.ToString());
            Debug.Print("Exception: " + e.ToString());
            return null;
        }
    }
}
